/* save the context in process in kernel space */
.macro ksave
		 movl %eax, -4(%esp)
		 movl %ecx, -8(%esp)
		 movl %edx, -12(%esp)
		 movl %ebx, -16(%esp)
		 movl %edi, -20(%esp)
		 movl %esi, -24(%esp)
		 movl %ebx, -28(%esp)	
.endm	

/* restore the context of process in kernel space */	 
.macro krestore
		movl -4(%esp),  %eax
		movl -8(%esp),  %ecx
		movl -12(%esp), %edx
		movl -16(%esp), %ebx
		movl -20(%esp), %edi
		movl -24(%esp), %esi
		movl -28(%esp), %ebp
		jmp *%esp
.endm


#
# prototype : int do_switch(struct proc *pick_proc);
# function :  save current process's context and switch to a new process
#
.set PID,	0
.set STATUS,	16
.set CONTEXT,	32

.set RUN,	0
.set READY,	1

.set ESP0,	(CONTEXT + 0)
.set CR3,	(CONTEXT + 4)
	
.globl do_switch
.extern cur_proc
.extern tss_switch
do_switch:
			pushl %ebp
			movl %esp,%ebp
			subl $0x20,%esp
			
			
			# save context
			movl $__k_eip, (%esp)
			ksave
			
			# make current process's status be READY
			movl cur_proc, %eax
			movl $READY, STATUS(%eax)
			
			# switch process and make the new process's status be RUN
			movl 8(%ebp), %eax
			movl $RUN, STATUS(%eax)
			movl %eax, cur_proc
			
			# switch to new process
__switch_to:
			movl CR3(%eax), %ebx
			movl %ebx, %cr3
			
			movl ESP0(%eax), %ebx
			movl %ebx, %esp
			
			krestore
			
			call tss_switch
			
			# __k_eip is the return address of every process in
			# kernel space
__k_eip:			
			movl %ebp,%esp
			popl %ebp
			ret


#
# prototype : int kputc(char ch);
# always destroy eax and ebx
#
.globl kputc
kputc:
			pushl %ebp
			movl %esp,%ebp
			subl $0x10,%esp
			
			movl %edi, (%esp)

			call vga_addr

			xorl %eax,%eax
			movl 8(%ebp),%ebx
			movb $0x07,%bh		# attribute of character
			movw %bx,(%edi)

			movl (%esp), %edi
			movl %ebp,%esp
			popl %ebp
			ret

# EOF

